<!DOCTYPE html>
<html>
   <head>
      <script src="../../../Grid/GridE.js"> </script>
   </head>
   <body class="Example">
      <style>
         /* Examples shared styles */
         .Example h1,.Example h2,.Example ul,.Example .Desc,.Example .Path,.Example .Xml { max-height:999999px; }
         .Example h1 { font:30px Arial; padding:5px 0px 5px 0px; margin:0px; text-align:center; }
         .Example h2 { font:15px Arial; padding:0px; margin:0px 0px 10px 0px; text-align:center; color:#757575; }
         .Example h3,.Example h4 { display:inline-block; font:bold 15px/17px Arial; padding:0px 5px 0px 5px; border-radius:2px; margin:2px; color:#333; }
         .Example h3 { background:#EE9; border:1px solid #DD8; }
         .Example h4 { background:#BDE; border:1px solid #ACD; }
         .Example a { text-decoration:underline; }      
         .Example li { padding-bottom:8px; }
         .Example ul { margin:6px 0px 0px 0px; font:13px/16px Arial; }    
         .Example > ul { margin-left:0px; padding-left:15px; clear:both; }
         .Example ul b { color:#0585B9; }
         .Example .Desc { margin:0px 5px 10px 5px; padding:10px; border:1px solid #dfdfdf; font:14px/17px Arial; }
         .Example .Desc b { color:#0585B9; }
         .Example .Path { font:normal 12px Arial; color:#0585B9; }
         .Example .Path b { color:#D73938; }
         .Example .Path u { text-decoration:none; color:black; font-weight:bold; padding:0px 2px 0px 2px; }
         .Example .Path i { color:black; font-style:normal; font-weight:bold; }
         .Example .Xml { margin-bottom:6px; font:11px/14px Arial; color:#757575; }
         .Example .Border { margin:0px 5px 15px 5px; }
         .Example .Main { }
         @media (max-height:800px) { 
            .Example .Desc { font-size:13px; line-height:15px; margin:0px 5px 5px 5px; padding:3px 5px; } 
            .Example .Border { margin-bottom:0px; }
            .Example h1 { font:20px Arial; padding:0px; }
            .Example h2 { font:12px Arial; }
            }
         @media (max-height:650px) {
            .Example h2 { display:none; }
            }

         /* --- Styles used in this example in created boxes HTML --- */
         .Top,.TopLeft { width:10px; height:10px; float:left; border-top:1px dotted gray; border-right:1px dotted gray; overflow:hidden; }
         .TopLeft { border-left:1px dotted gray; }
         .BackWhite { background:white; }
         .BackGreen { background:#6D8; }
         .BackYellow { background:#EE6; }
         .BackRed { background:#D86; }
         .Box { border:1px dotted black; border-top-right-radius:10px; font-size:12px; line-height:14px; }
         .Big { font-size:14px; }
         .Bold { color:blue; font-weight:bold; }
         .Small { font-size:8px; line-height:10px; border:1px dotted black; border-top:none; width:100%; overflow:hidden; }
         .Bottom { float:left; overflow:hidden; border-right:1px dotted black; border-bottom:1px dotted black; font-size:12px; line-height:14px; }
         .Width { width:100%; overflow:hidden; }
         .Height12 { height:14px; }
         .Height16 { height:16px; }
         .Left { width:100%; overflow:hidden; border-left:1px dotted black; }

         .VAlign { vertical-align:middle; }
         .Inner { padding-top:8px; }
         .Group { padding-left:15px; }

         .White { background:#FFFFFF; }
         .Cyan { background:#6DE; }
         .Blue { background:#ADD8E6; }
         .Yellow { background:#EE6; }
         .Lime { background:#00FF00; }
         .Silver { background:#C0C0C0; }
         .Orange { background:#EA6; }
         .Green { background:#40C040; }

         .Deleted { background:#DDD; color:#AAA; }

         .GBGanttMainIn,.GBFGanttBase { color:black; } /* Slightly changes the look for inverse Black style */
         .TSCellRotate *,.TWCellRotate *,.TBCellRotate *,.TMCellRotate *,.TTCellRotate * { text-overflow:clip; } /* Displays the rotated text as long as possible */

         /* --- */

      </style>

      <script>
// -----------------------------------------------------------------------------------------------------------------------------------------
// Browser identification
var BIEA = navigator.appName.search("Microsoft")>=0 || navigator.userAgent.search("Trident")>=0; // True if Browser = Internet explorer
var BIE = BIEA && document.compatMode!="CSS1Compat" && !(document.documentMode>=10); // True if Internet explorer is in quirks mode 5

// -----------------------------------------------------------------------------------------------------------------------------------------
// Creates the Main bar content HTML (in child row)
Grids.OnGetGanttHtml = function(G,row,col,width,comp,crit,plan,idx,txt,w,maxw,cls,exp){
width -= 4; // border size around the box, can differ according to used TreeGrid CSS style
var dur = Get(row,"DUR");
var W = [Math.floor(Get(row,"R1")*width/100),Math.floor(Get(row,"R2")*width/100),Math.floor(Get(row,"R3")*width/100)];
W[3] = (width-W[0]-W[1]-W[2]);
if(W[3]<0) W = [0,0,0,0]; // Wrong data, negative result !
if(!BIE){ // Subtracts tag borders (1px), because width does not contain them. All browsers except IE quirks mode
   for(var i=0;i<W.length;i++) if(W[i]) W[i]--;
   }
for(var i=W.length-1;i>=0;i--) if(W[i]) { W[i]--; break; } // The left tag border, once
if(exp) {
   cls[0] = G.GetString(row,"COLOR");
   return "<span style='color:"+Get(row,"I1")+"'>o</span><span style='color:"+Get(row,"I2")+"'>o</span><span style='color:"+Get(row,"I3")+"'>o</span><span style='color:"+Get(row,"I4")+"'>o</span> &#x20; "
      +"<span style='color:green;'>"+NumberToString(Get(row,"R1")*dur/100,"0.##")+"</span> &#x20; "
      +"<span style='color:yellow;'>"+NumberToString(Get(row,"R2")*dur/100,"0.##")+"</span> &#x20; "
      +"<span style='color:red;'>"+NumberToString(Get(row,"R3")*dur/100,"0.##")+"</span> &#x20; "
      +"<span style='color:gray;'>"+NumberToString((100-Get(row,"R1")-Get(row,"R2")-Get(row,"R3"))*dur/100,"0.##")+"</span><br/>"
      +"<span style='font-weight:bold;color:blue;'>"+Get(row,"CITY")+"</span> \t "+Get(row,"COMP")+"%<br/>"
      +Get(row,"CN")+" \t "+dur+" hours";
   }
return "<div class='Width' style='padding-top:2px;'>"
      +"<div class='TopLeft Back"+Get(row,"I1")+"'></div>"
      +"<div style='display:"+(width<=22?"none":"")+"' class='Top Back"+Get(row,"I2")+"'></div>"
      +"<div style='display:"+(width<=33?"none":"")+"' class='Top Back"+Get(row,"I3")+"'></div>"
      +"<div style='display:"+(width<=44?"none":"")+"' class='Top Back"+Get(row,"I4")+"'></div>"
   +"</div>"
   +"<div class='Box "+(row.Deleted ? "Deleted" : G.GetString(row,"COLOR"))+"'>"
      +"<div class='Width Height16'>"
         +"<div style='float:right;padding-right:2px;' class='Big'>"+Get(row,"COMP")+"%</div>"
         +"<div class='Big Bold"+(row.Deleted?" Deleted":"")+"'>"+Get(row,"CITY")+"</div>"
      +"</div>"
      +"<div class='Width Height12'>"
         +"<div style='float:right;padding-right:2px;'>"+dur+" hours</div>"
         +"<div>"+Get(row,"CN")+"</div>"
      +"</div>"
      
   +"</div>"
   +"<div class='Width'><div class='Left'>"
   +(W[0]?"<div class='BackGreen Bottom' style='width:"+W[0]+"px'>"+NumberToString(Get(row,"R1")*dur/100,"0.##")+"</div>":"")
   +(W[1]?"<div class='BackYellow Bottom' style='width:"+W[1]+"px'>"+NumberToString(Get(row,"R2")*dur/100,"0.##")+"</div>":"")
   +(W[2]?"<div class='BackRed Bottom' style='width:"+W[2]+"px'>"+NumberToString(Get(row,"R3")*dur/100,"0.##")+"</div>":"")
   +(W[3]?"<div class='BackWhite Bottom' style='width:"+W[3]+"px'>"+NumberToString((100-Get(row,"R1")-Get(row,"R2")-Get(row,"R3"))*dur/100,"0.##")+"</div>":"")
   +"</div></div>";
}
// -----------------------------------------------------------------------------------------------------------------------------------------
// Creates the Run box content HTML according to its children (in group row)
Grids.OnGetGanttRunText = function(G,row,col,run,index,text,width,x,maxw,cls,exp){
var cr = G.GetRowById(run[index][5]);
if(cr) return Grids.OnGetGanttHtml(G,cr,col,width-G.BoxPadding,null,null,null,null,null,null,null,cls,exp);      // The BoxPadding is custom value and can differ according to used TreeGrid CSS style
else return Grids.OnGetGanttHtml(G,G.Def.New,col,width-G.BoxPadding,null,null,null,null,null,null,null,cls,exp); // For new run box returns text for default row <D Name='New'/>
}

// -----------------------------------------------------------------------------------------------------------------------------------------
// Used to display edit box for Rotated cells
Grids.OnCustomStartEdit = function(G,row,col,val,cell,width){
if(G.GetType(row,col)=="Enum" || !G.GetAttribute(row,col,"Rotate")) return; // Only for rotated cell, but not Enum
G.Prompt("Enter value for "+G.Header[col],val,function(res){ 
   G.EndEdit(0);
   if(res!=null) {
      res = G.CheckGantt(row,col,res);
      if(res!==false) G.SetValue(row,col,res,1);
      }
   },100);
return true;
}
Grids.OnCustomEndEdit = function(){ } // Unused, but required to define
// -----------------------------------------------------------------------------------------------------------------------------------------
// Updates dependencies for deleted row - links the previous and next rows together
Grids.OnRowDelete = function(G,row){
var next = Get(row,"NEXT"), prev = Get(row,"PREV");
if(next) { 
   var nr = G.GetRowById(next), val = G.CheckGantt(nr,"PREV",prev); 
   if(val!==false) G.SetValue(nr,"PREV",val,1); 
   }
if(prev) { 
   var pr = G.GetRowById(prev), val = G.CheckGantt(pr,"NEXT",next); 
   if(val!==false) G.SetValue(pr,"NEXT",val,1); 
   }
}
// -----------------------------------------------------------------------------------------------------------------------------------------
// Updates dependencies for new or undeleted row - finds the boxes between the row's box will be added and links it to them
Grids.OnRowUndelete = function(G,row){
var max = -1e16, found = null, start = Get(row,"START");
if(start==="" && row.previousSibling) start = Get(row.previousSibling,"START");
for(var r=row.parentNode.firstChild;r;r=r.nextSibling){
   if(r==row || r.Deleted) continue;
   var s = Get(r,"START");
   if(s>max && s<=start){ found = r; max = s; }
   }
if(found){ // found is the nearest box starting before the row's box, adds the row's box after it
   G.MoveRow(row,row.parentNode,found.nextSibling,1);
   if(Get(found,"NEXT")){
      var nr = G.GetRowById(Get(found,"NEXT"));
      var val = G.CheckGantt(nr,"PREV",row.id); 
      if(val!==false) G.SetValue(nr,"PREV",val,1); 
      }
   var val = G.CheckGantt(found,"NEXT",row.id); 
   if(val!==false) G.SetValue(found,"NEXT",val,1); 
   }
else { // All boxes are after the box, searches for the first box
   var min = 1e16;
   for(var r=row.parentNode.firstChild;r;r=r.nextSibling){
      if(r==row || r.Deleted) continue;
      var s = Get(r,"START");
      if(s<min){ found = r; min = s; }
      }
   if(found){ // The first box, adds the row's box before it
      G.MoveRow(row,row.parentNode,found,1);
      var val = G.CheckGantt(row,"NEXT",found.id); 
      if(val!==false) G.SetValue(row,"NEXT",val,1); 
      }
   }
}
// -----------------------------------------------------------------------------------------------------------------------------------------
// Calls the OnRowUndelete also for added rows, but not when pasting new rows
Grids.OnRowAdded = function(G,row,paste){ if(!paste) return Grids.OnRowUndelete(G,row); } 
// -----------------------------------------------------------------------------------------------------------------------------------------
// Called during dragging and on drop
Grids.OnGanttRunDrop = function(G,row,col,drop,src,index,keyprefix,x,y,togrid,torow,tocol,cellx,accept){
if(torow && row.Level!=torow.Level) return false; // Cannot move the Run to different level
if(drop && row==torow){ // When moved (not only shifted) Run box inside one row
   var row = G.GetRowById(src[0][5]);
   setTimeout(function(){ // Called in timeout because in time of the event call the Run is not yet set
      Grids.OnRowDelete(G,row); // Simulates delete and undelete to regenerate dependencies for the new position
      Grids.OnRowUndelete(G,row);
      },10);
   }
}
// -----------------------------------------------------------------------------------------------------------------------------------------
// Called on moving row in grid
Grids.OnRowMove = function(G,row,oldparent,oldnext){
if(row.parentNode!=oldparent){ // When moved Run box to another row
   setTimeout(function(){ // Called in timeout because in time of the event call the Run is not yet set
      Grids.OnRowDelete(G,row); // Simulates delete and undelete to regenerate dependencies for the new position
      Grids.OnRowUndelete(G,row);
      },10);
   }
}
// -----------------------------------------------------------------------------------------------------------------------------------------
// Called to get cell value for filtering to be used instead of the cell value
// It is used to get value for filtering by GROUP (Location), the grouped column
Grids.OnGetFilterValue = function(G,row,col,val){
if(col=="GROUP" && row.Def.Name=="R") val = Get(row,"REG")+","+Get(row,"CN");
return val;
}
// ------------------------------------------------------------------------------------------------------------
// Called when NoVScroll / NoHScroll is set automatically due small window size
// First time it hides resource usage rows. Sets OnceLimit custom attribute to not run it again if a user shows the resource rows again
Grids.OnLimitScroll = function(G,clr,noh,nov){ 
if(G.Rows[-2].Visible&&!clr&&!G.OnceLimit){
   G.OnceLimit = 1;
   var F = G.GetRows(G.Foot); G.StartUpdate();
   for(var i=0;i<F.length;i++) G.HideRow(F[i]); 
   G.EndUpdate();
   G.SetValue(G.Rows.Group,"HidRes",1,1);
   return -1;
   }
}
// -----------------------------------------------------------------------------------------------------------------------------------------

      </script>
      <center class="Path"><script>document.write(location.href.replace(/(.*)(\/Examples\/|\/ExamplesGantt\/)([^\/]+)\/([^\/]+)\/([^\/]+)$/,"$2<b>$3</b>/<i>$4</i>/$5").replace(/([^<]|^)(\/|\.)/g,"$1<u>$2</u>"));</script></center>
      <h1>Grouping main bars to Run groups</h1>
      <h2>Defining tasks as one individual main bar per row and grouping them by various criteria to Run groups</h2>
      <div class="Desc">
         The bars in Run groups can be <b>created, deleted, resized, moved</b> inside row, moved to another group <i>(by right mouse button)</i>. 
         All the changes are done also in underlying main bars.<br />
         The changes to server are usually saved only in the main bars.
         It is even possible to hide the main bars and show only the Run groups.<br />
         This example also demonstrates <b>custom HTML bar content</b>, for both Run and main bar. 
         And <b>correcting dependencies in MS Project</b> way with early start constraint.<br />
      </div>
      <div class="Border">
         <div class="Main">
            <bdo Layout_Url='RunGroupDef.xml' Data_Url='RunGroupData.xml'></bdo>
         </div>
      </div>

      <!-- Google Analytics code run once for trial -->
      <script>
         var TGTrial = document.cookie.match(/TGTrialGantt\s*=\s*(\d+)/), TGIndex = 1024;
         if(!TGTrial||!(TGTrial[1]&TGIndex)) setTimeout(function(){
            var n = "RunTrialHtmlRunGroup", d = (new Date((new Date).getTime()+31536000000)).toUTCString(); document.cookie = "TGTrialGantt="+((TGTrial?TGTrial[1]:0)|TGIndex)+";expires="+d;
            var u = document.cookie.match(/TGTrialUsed\s*=\s*(\d+)/); u = u ? u[1]-0+1 : 1; if(u<=11) document.cookie = "TGTrialUsed="+u+";path=/;expires="+d;
            var s = "<div style='width:0px;height:0px;overflow:hidden;'><iframe src='http"+(document.location.protocol=="https"?"s":"")+"://www.treegrid.com/Stat/GA.html?productName="
                 +(u==1||u==3||u==5||u==10?"UsedTrial"+u:n)+"' onload='var T=this;setTimeout(function(){document.body.removeChild(T.parentNode.parentNode);},1000);'/></div>";
            var F = document.createElement("div"); F.innerHTML = s; document.body.appendChild(F);
            },100);
      </script>
   </body>
</html>